package com.gbase8c.dmt.migration;

import com.alibaba.fastjson.JSON;
import com.gbase8c.dmt.model.migration.record.Mo;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@Slf4j
public class MoLogger {
    private final ConcurrentHashMap<String, Mo> map = new ConcurrentHashMap<>();
    private final Logger logger;
    private Thread thread;

    public MoLogger(String workDir, String taskId, String type) {
        File file = file(workDir, taskId, type);
        logger = new Logger(file, map);
    }

    public MoLogger(String workDir, String taskId, String type, long wait) {
        File file = file(workDir, taskId, type);
        logger = new Logger(file, map, wait);
    }

    private File file(String workDir, String taskId, String type) {
        String filePath = StringUtils.joinWith(File.separator, workDir, taskId, "status", type + ".json");
        return new File(filePath);
    }

    public void start() {
        thread = new Thread(logger);
        thread.start();
    }

    public void stop() {
        try {
            logger.setStop(true);
            thread.join();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void log(Mo mo) {
        map.put(mo.getName(), mo);
    }

    @Getter
    @Setter
    @Slf4j
    public static class Logger implements Runnable {

        private ConcurrentHashMap<String, Mo> map;
        private long wait = 10000L;

        private File file;
        private volatile boolean stop = false;

        public Logger(File file, ConcurrentHashMap<String, Mo> map) {
            this.file = file;
            this.map = map;
        }

        public Logger(File file, ConcurrentHashMap<String, Mo> map, long wait) {
            this.file = file;
            this.map = map;
            this.wait = wait;
        }

        @Override
        public void run() {
            log.info("开始数据库对象状态更新: " + file.getPath());
            CountDownLatch latch = new CountDownLatch(1);
            initMap();
            String lastJson = JSON.toJSONString(map.values());
            while (!stop) {
                String newJson = JSON.toJSONString(map.values());
                if (!newJson.equalsIgnoreCase(lastJson)) {
                    lastJson = newJson;
                    try {
                        FileUtils.writeStringToFile(file, newJson, StandardCharsets.UTF_8);
                        latch.await(wait, TimeUnit.MILLISECONDS);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
            if (stop) {
                log.info("停止数据库对象状态更新: " + file.getPath());
                String newJson = JSON.toJSONString(map.values());
                if (!newJson.equalsIgnoreCase(lastJson)) {
                    try {
                        FileUtils.writeStringToFile(file, newJson, StandardCharsets.UTF_8);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }

        private void initMap() {
            try {
                List<Mo> mos = JSON.parseArray(FileUtils.readFileToString(file, StandardCharsets.UTF_8), Mo.class);
                for (Mo mo : mos) {
                    map.put(mo.getName(), mo);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

}
